import ustruct

# CRC-16-MODBUS

def calc_crc16(data, index, len = 0):
    if len == 0:
        len = len(data)
    # 初始化crc为0xFFFF
    crc = 0xFFFF

    # 循环处理每个数据字节
    for i in range(index, index + len):
        byte = data[i]
        # 将每个数据字节与crc进行异或操作
        crc ^= byte

        # 对crc的每一位进行处理
        for _ in range(8):
            # 如果最低位为1，则右移一位并执行异或0xA001操作(即0x8005按位颠倒后的结果)
            if crc & 0x0001:
                crc = (crc >> 1) ^ 0xA001
            # 如果最低位为0，则仅将crc右移一位
            else:
                crc = crc >> 1

    # 返回最终的crc值
    return crc

def read_hold_reg(devno, addr, len):
    buf = ustruct.pack('!BBHHI', devno, 0x03, addr, len, 0)
    crc = calc_crc16(buf)
    ustruct.pack_info('<H', buf, len(buf) - 2, crc)
    return buf

def read_input_reg(devno, addr, len):
    buf = ustruct.pack('!BBHHI', devno, 0x04, addr, len, 0)
    crc = calc_crc16(buf)
    ustruct.pack_info('<H', buf, len(buf) - 2, crc)
    return buf

def read_coil(devno, addr, len):
    buf = ustruct.pack('!BBHHI', devno, 0x01, addr, len, 0)
    crc = calc_crc16(buf)
    ustruct.pack_info('<H', buf, len(buf) - 2, crc)
    return buf

